import { CmdType } from '@renderer/model/base-enum';
import { packed } from './packData';

export class Communication {
  public _ip;
  public _port;
  public _client;
  public _sock = null as any;
  public _heartTimer = null as any;
  public _token;
  public _sessionId;
  private _sessionCleaned = false;
  private _disconnected = false;
  private _connectionId = '';
  private _listenersRegistered = false;
  private _socketReady = false;
  private _pendingPackets: any[] = [];
  constructor(client: any, ip: string, token: string, port: number, sessionId: string) {
    this._client = client;
    this._ip = ip;
    this._port = port;
    this._token = token;
    this._sessionId = sessionId;
    this._connectionId = `kvm-${this._ip}-${this._port}`;
  }

  start() {
    this._CreateConnection();
  }

  _CreateConnection() {
    const wssUrl = `wss://${this._ip}:${this._port}/websocket/kvm`;
    window.onbeforeunload = () => {
      this._Send(packed.packDisconnect());
      this._cleanupSession('before-unload');
      localStorage.removeItem('kvmConnected');
    };
    this._socketReady = false;
    this._disconnected = false;
    this._pendingPackets = [];
    this._registerEventListeners();
    const useCertificate = this._client.scope?.useCertificate === true;
    const tabId = this._client.scope?.tabId;
    window.api.websocket
      .connect(this._connectionId, wssUrl, useCertificate, tabId)
      .then((result: any) => {
        if (result.success) {
        } else {
          this._handleConnectionError(result.error);
        }
      })
      .catch((error: any) => {
        console.error('Error initiating WebSocket connection:', error);
        this._handleConnectionError(error);
      });
  }

  _registerEventListeners() {
    if (this._listenersRegistered) {
      try {
        window.api?.websocket?.removeAllListeners?.('websocket-status');
        window.api?.websocket?.removeAllListeners?.('websocket-message');
        window.api?.websocket?.removeAllListeners?.('websocket-error');
      } catch (error) {
        console.warn('Failed to remove old WebSocket listeners:', error);
      }
    }
    this._listenersRegistered = true;

    // 监听连接状态
    window.api.websocket.onStatus((data: any) => {
      if (data.connectionId === this._connectionId) {
        if (data.status === 'connected') {
          this._WSOpen(data);
        } else if (data.status === 'disconnected') {
          this._WSClose(data);
        }
      }
    });

    // 监听消息
    window.api.websocket.onMessage((data: any) => {
      if (data.connectionId === this._connectionId) {
        this._WSMessage(data);
      }
    });

    // 监听错误
    window.api.websocket.onError((data: any) => {
      if (data.connectionId === this._connectionId) {
        this._WSError(data);
      }
    });
  }
  _WSOpen(event: any) {
    this._disconnected = false;
    this._socketReady = true;
    this._sendThroughBridge(packed.packConnect(this.getKvmToken()));
    this._flushPendingPackets();

    if (this._client.scope?.tabId) {
      const connectionPayload = {
        tabId: this._client.scope.tabId,
        connectionId: this._connectionId,
        sessionId: this._sessionId,
        webSessionId: this._client.scope?.webSessionId,
        baseUrl: this._client.scope.baseUrl,
        csrfToken: this._client.scope.csrfToken,
        cookie:
          this._client.scope.cookieName && this._client.scope.cookieValue
            ? {
                name: this._client.scope.cookieName,
                value: this._client.scope.cookieValue
              }
            : undefined
      };
      try {
        window.electron?.ipcRenderer?.send('tab-conn-info-report', connectionPayload);
      } catch (error) {
        console.error('Failed to send tab connection info:', error);
      }
    }
  }
  _WSClose(event: any) {
    this._socketReady = false;
    this._pendingPackets = [];
    this._disconnected = true;
    clearInterval(this._heartTimer);
    localStorage.removeItem('kvmConnected');

    // code值1008表示KVM会话超时
    if (event?.code === 1008) {
      this._cleanupSession('timeout');
      this._client.scope.dialogClickOK = () => {
        this._cleanupSession('timeout-dialog-close');
        this._navigateToLogin();
      };
      this._client.showMessage(
        'REMOTE_ERR_TIMEOUT',
        'disconnectDialog',
        'HOME_PERFWARNING',
        'warning',
        true
      );
    } else if (event?.code === 4001) {
      // code值4001表示KVM会话被强制踢出
      this._cleanupSession('forced-logout');
      this._client.scope.dialogClickOK = () => {
        this._cleanupSession('forced-logout-dialog-close');
        this._navigateToLogin();
      };
      this._client.showMessage(
        'REMOTE_FORCED_LOGOUT_KVM',
        'logoutDialog',
        'HOME_PERFWARNING',
        'warning',
        true
      );
    } else if (event?.code === 1000 || event?.code === 1001) {
      this._cleanupSession('normal-close');
    } else if (event?.code === 1015) {
      this._cleanupSession('tls-handshake-failure');
    } else {
      this._cleanupSession(event?.code === 1006 ? 'abnormal-close' : 'disconnect');
      this.notifyNetworkInterrupt();
    }
    this._client._toolbar._virtualMedia._Reset();
  }
  _WSError(event: any) {
    this._socketReady = false;
    this._pendingPackets = [];
    console.error('WebSocket error:', event);
    this.notifyNetworkInterrupt();
  }

  _WSMessage(event: any) {
    const data = new Uint8Array(event?.data);
    // 更新界面右下角接收数据(Recv)的值
    this._client._statusbar.updateRecive(data.length);
    const { bodyDataLength, cmdType, bodyData } = packed.parseData(data);
    switch (cmdType) {
      case CmdType.CONNECT_RSP_S:
        this.dealConnectRsp(bodyData);
        break;
      case CmdType.IMAGE_DATA_REQ_S:
        // 图像数据
        this.dealImageRsp(bodyDataLength, bodyData);
        break;
      case CmdType.GET_IMAGE_RESOLUTION_RSP_S:
        this.updateImageResolution(bodyData);
        break;
      case CmdType.POWER_CONTROL_RSP_S:
        this.showResponseTip(bodyData);
        break;
      case CmdType.GET_BOOT_OPTION_RSP_S:
        // 接收启动项的当前选中项
        this._client._toolbar.setBootOption(bodyData[0]);
        break;
      case CmdType.SET_BOOT_OPTION_RSP_S:
        // 接收系统启动项设置成功与否状态
        this.showResponseTip(bodyData);
        break;
      case CmdType.GET_MOUSE_MODE_RSP_S:
        this.updateMouseMode(bodyData);
        break;
      case CmdType.KEYBOARD_STATUS_RSP_S:
        this.dealKeyboardLight(bodyData);
        break;
      case CmdType.VMM_ENABLE_RSP_S:
        this._client._toolbar._virtualMedia.parserVmmState(bodyData[0]);
        break;
      case CmdType.VMM_PORT_RSP_S:
        this.getVmmPort(bodyData);
        break;
      case CmdType.CUSTOM_DATA_GET_R:
        this.getCustom(bodyData);
        break;
      case CmdType.CUSTOM_DATA_SAVE_R:
        this.getErr(bodyData, 'save');
        break;
      case CmdType.CUSTOM_DATA_DEL_R:
        this.getErr(bodyData, 'delete');
        break;
      default:
        break;
    }
  }

  // token字符串转义
  getKvmToken() {
    const tokenLength = this._token?.length;
    const buffer = new Uint8Array(tokenLength);
    for (let i = 0; i < tokenLength; i++) {
      buffer[i] = this._token.charCodeAt(i);
    }
    return [...buffer];
  }

  async deleteKvmUser(sessionId: string) {
    if (!sessionId) {
      return;
    }
    const scope = this._client?.scope;
    const baseUrl = scope?.baseUrl;
    const csrfToken = scope?.csrfToken;
    const cookieName = scope?.cookieName;
    const cookieValue = scope?.cookieValue;
    if (!baseUrl || !csrfToken || !cookieName || !cookieValue) {
      return;
    }
    const logoutUrl = `${baseUrl}/UI/Rest/Sessions/${sessionId}`;
    try {
      await window.api?.fetchData?.({
        method: 'delete',
        url: logoutUrl,
        headers: {
          From: 'WebUI',
          'X-CSRF-Token': csrfToken,
          cookie: `${cookieName}=${cookieValue}`
        }
      });
    } catch (error) {
      console.error(`Logout failed for ${sessionId}:`, error);
    }
  }

  async logoutWebSession(trigger: string) {
    const scope = this._client?.scope;
    const webSessionId = scope?.webSessionId;
    const baseUrl = scope?.baseUrl;
    const csrfToken = scope?.csrfToken;
    const cookieName = scope?.cookieName;
    const cookieValue = scope?.cookieValue;
    if (!webSessionId || !baseUrl || !csrfToken || !cookieName || !cookieValue) {
      return;
    }
    const logoutUrl = `${baseUrl}/UI/Rest/Sessions/${webSessionId}`;
    try {
      await window.api?.fetchData?.({
        method: 'delete',
        url: logoutUrl,
        headers: {
          From: 'WebUI',
          'X-CSRF-Token': csrfToken,
          cookie: `${cookieName}=${cookieValue}`
        }
      });
    } catch (error) {
      console.error(`Web session logout failed, trigger=${trigger}`, error);
    }
  }

  dealConnectRsp(bodyData: Uint8Array) {
    if (bodyData[0] === 0) {
      // 连接成功后发送查询图像分辨率请求
      this._Send(packed.packGetImageResolution());
      // 发送强制I帧请求,连接成功后立即有完整图像
      this._Send(packed.packForceIFrame());
      // 发送鼠标初始状态请求
      this._Send(packed.packGetMouseMode());
      // 发送键盘初始化状态
      this._Send(packed.packInitKeyBoard());
      // 发送查询启动项选中项请求
      this._Send(packed.packGetBootOption());
      // 发送查询自定义按键
      this._Send(packed.packGetCustom());
      localStorage.setItem('kvmConnected', JSON.stringify(true));
    }
  }

  dealImageRsp(bodyDataLength: number, bodyData: Uint8Array) {
    const imageBody = packed.parseImageBody(bodyData);
    if (bodyDataLength === imageBody.imageLength + 10) {
      this._client._display.drawImage(imageBody);
    }
    // 接收到图像信息时发送一次心跳
    this._Send(packed.packHeartBeat());
  }

  updateImageResolution(bodyData: Uint8Array) {
    this._client._toolbar._slider.value = bodyData[0];
  }

  updateMouseMode(bodyData: Uint8Array) {
    this._client._toolbar.setMouseAcceleration(bodyData[0]);
  }

  dealKeyboardLight(bodyData: Uint8Array) {
    this._client._toolbar.setKeyboardLight(bodyData[0]);
  }

  getVmmPort(data: Uint8Array) {
    const port = (data[0] << 8) + data[1];
    this._client._toolbar._virtualMedia.parserVmmPort(port);
  }

  getCustom(data: Uint8Array): void {
    this._client._toolbar._CustomData(data);
  }

  getErr(data: Uint8Array, type: any): void {
    this._client._toolbar._CustomErrData(data, type);
  }

  public showResponseTip(bodyData: Uint8Array) {
    let contentInfo = '';
    let id = 'ResponseSuccessTip';
    let title = '';
    let type = '';
    switch (bodyData[0]) {
      case 0:
        contentInfo = 'COMMON_SUCCESS';
        break;
      case 1:
        contentInfo = 'COMMON_FAILED';
        type = 'warning';
        break;
      case 2:
        contentInfo = 'HOME_NO_ACCESS';
        type = 'error';
        break;
      default:
        break;
    }

    this._client.showMessage(contentInfo, id, title, type);
  }

  _Send(data: any) {
    if (this._disconnected) {
      return;
    }
    if (!data?.buffer) {
      return;
    }

    if (!this._socketReady) {
      this._pendingPackets.push(data);
      return;
    }

    this._sendThroughBridge(data);
  }

  private _sendThroughBridge(data: any) {
    this._client._statusbar.updateSend(data.length);
    window.api.websocket
      .send(this._connectionId, data.buffer)
      .then((result: any) => {
        if (!result.success) {
          console.error('Failed to send data:', result.error);
          if (result.error && result.error.includes('WebSocket is not connected')) {
            this.notifyNetworkInterrupt();
          }
        }
      })
      .catch((error: any) => {
        console.error('Error sending data:', error);
        if (
          error &&
          (error.toString().includes('WebSocket is not connected') ||
            error.message?.includes('WebSocket is not connected'))
        ) {
          this.notifyNetworkInterrupt();
        }
      });
  }

  private _flushPendingPackets() {
    if (!this._pendingPackets.length) {
      return;
    }
    const queued = this._pendingPackets.slice();
    this._pendingPackets = [];
    queued.forEach((packet) => {
      if (!packet?.buffer) {
        return;
      }
      if (this._disconnected || !this._socketReady) {
        return;
      }
      this._sendThroughBridge(packet);
    });
  }

  _handleConnectionError(error: any) {
    this._socketReady = false;
    console.error('Connection error:', error);
    this.notifyNetworkInterrupt();
  }

  destroy() {
    clearInterval(this._heartTimer);
    if (!this._disconnected) {
      this._Send(packed.packDisconnect());
    }
    this._cleanupSession('destroy');
    // 退出Web会话
    void this.logoutWebSession('destroy');
    // 断开WebSocket连接
    window.api.websocket.disconnect?.(this._connectionId);
  }

  private _cleanupSession(trigger: string) {
    if (this._sessionCleaned) {
      return;
    }
    this._sessionCleaned = true;
    if (!this._sessionId) {
      return;
    }
    void this.deleteKvmUser(this._sessionId);
  }

  private notifyNetworkInterrupt() {
    if (this._disconnected) {
      return;
    }
    this._socketReady = false;
    this._pendingPackets = [];
    this._disconnected = true;
    this._cleanupSession('network-interrupt');
    this._client.scope.dialogClickOK = () => {
      this._navigateToLogin();
    };
    this._client.showMessage(
      'REMOTE_ERR_NETWORK_INTERRUPT',
      'networkInterruptDialog',
      'COMMON_ERROR',
      'error'
    );
    window.api.websocket.disconnect?.(this._connectionId);
  }
  // 检查WebSocket连接状态
  isConnected(): boolean {
    return !this._disconnected && localStorage.getItem('kvmConnected') !== null;
  }

  // 跳转到登录页
  private async _navigateToLogin() {
    await this.logoutWebSession('error-navigate-to-login');
    window.api.websocket.disconnect?.(this._connectionId);
    this._resetWebSocketState();
    const tabId = this._client.scope?.tabId;
    if (tabId) {
      try {
        await window.api?.session?.clear?.(tabId);
        setTimeout(() => {
          try {
            window.electron?.ipcRenderer?.send('tab-conn-info-report', {
              tabId,
              clear: true
            });
          } catch (error) {
            console.error(`Failed to send clear tab connection info for tab ${tabId}:`, error);
          }
        }, 100);
      } catch (error) {
        console.error(`Failed to clear session for tab ${tabId}:`, error);
      }
    }
    window.location.href = '#/login';
  }

  // 重置WebSocket状态
  private _resetWebSocketState() {
    this._socketReady = false;
    this._disconnected = true;
    this._pendingPackets = [];
    clearInterval(this._heartTimer);
    this._heartTimer = null;
    localStorage.removeItem('kvmConnected');
    // 移除WebSocket监听器
    if (this._connectionId) {
      try {
        window.api?.websocket?.removeAllListeners?.('websocket-status');
        window.api?.websocket?.removeAllListeners?.('websocket-message');
        window.api?.websocket?.removeAllListeners?.('websocket-error');
      } catch (error) {
        console.warn('Failed to remove WebSocket listeners:', error);
      }
    }
  }
}
